Skip to content

feat: add migration for blast radius analysis (CM-1328)#4374

Merged
ulemons merged 1 commit into
mainfrom
feat/add-blast-radius-migrations
Jul 22, 2026
Merged

feat: add migration for blast radius analysis (CM-1328)#4374
ulemons merged 1 commit into
mainfrom
feat/add-blast-radius-migrations

Conversation

@ulemons

@ulemons ulemons commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the database schema for the blast-radius analysis pipeline (CM-1328). This PR is migrations only — it lays the ground for replicating the blast-radius PoC pipeline (intel → dependents → reachability → report) on top of the new blast-radius worker, backed by the database instead of the PoC's per-run JSON files under data/<VULN-ID>/. API/data-access-layer wiring lands in a follow-up PR.

Changes

  • New Flyway migration backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql, adding 5 tables:
    • blast_radius_analyses — one row per submitted job (id matches the analysisId already generated by submitBlastRadiusJob). Stores the raw advisory_osv_id / package_name from the request plus nullable advisory_id / package_id FKs, resolved later — the advisory or package may not be ingested yet when the job is submitted.
    • blast_radius_symbol_specs — stage 1 (intel) output, 1:1 with an analysis.
    • blast_radius_dependents — stage 2 output; unifies the PoC's "analyzed" and "excluded_by_range" dependent lists into one table via an excluded_by_range flag, since excluded candidates never get a resolved version/tarball.
    • blast_radius_verdicts — stage 3 output, 1:1 with a non-excluded dependent, including per-verdict cost_usd/turns_used/model.
    • blast_radius_stage_runs — dedicated performance-monitoring table: one row per (analysis, stage) tracking duration_ms/cost_usd/model, kept independent of the ecosystem-specific tables so it keeps working as more ecosystems are added.
  • The aggregated report (naive vs. true blast radius, bucket counts) is intentionally not materialized in its own table — it's derived from blast_radius_verdicts at read time to avoid keeping a denormalized copy in sync.
  • Migration is purely additive (CREATE TABLE/INDEX IF NOT EXISTS, no ALTER on existing tables) — no lock risk on packages/advisories in production.
  • Verified end-to-end by applying the full migration history against a live packages-db image (built from scripts/packages-db/Dockerfile, which includes pg_partman).

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Performance improvement
  • Chore / dependency update
  • Documentation

JIRA ticket

CM-1328

@ulemons ulemons self-assigned this Jul 21, 2026
Copilot AI review requested due to automatic review settings July 21, 2026 14:20
@ulemons ulemons added the Feature Created by Linear-GitHub Sync label Jul 21, 2026
@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Additive schema only with optional FKs to existing advisories/packages; no application logic or migrations on production tables in this PR.

Overview
Adds Flyway migration V1784700000__blast_radius_analyses.sql so the blast-radius worker can persist pipeline state in Postgres instead of the PoC’s per-run JSON under data/<VULN-ID>/.

blast_radius_analyses holds one row per job, with id aligned to the analysisId from submitBlastRadiusJob, raw request fields (advisory_osv_id, package_name), nullable FKs to advisories/packages filled later, status/cost/timing, and stage-2 population metadata. blast_radius_symbol_specs, blast_radius_dependents (analyzed + range-excluded via excluded_by_range), and blast_radius_verdicts store intel, dependents, and reachability outputs. blast_radius_stage_runs tracks per-stage duration, cost, and model. Aggregated report metrics are not stored; they are computed from verdicts at read time.

The change is additive only (CREATE TABLE / CREATE INDEX IF NOT EXISTS); no existing tables are altered.

Reviewed by Cursor Bugbot for commit fb94246. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds PostgreSQL persistence for the four-stage blast-radius analysis pipeline.

Changes:

  • Adds schemas for analyses, symbol specifications, dependents, verdicts, and stage runs.
  • Adds integrity constraints and query indexes.
  • Keeps aggregate reports derived from verdict data.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings July 22, 2026 10:08
@ulemons
ulemons force-pushed the feat/add-blast-radius-migrations branch from b2dd456 to 99915ef Compare July 22, 2026 10:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:97

  • These two foreign keys are independent, so the database accepts a verdict whose analysis_id is analysis A while dependent_id belongs to analysis B. Queries aggregating directly by blast_radius_verdicts.analysis_id would then report cross-analysis data. Enforce the pair with a composite foreign key to the dependent's (id, analysis_id), or remove the redundant analysis ID and derive it through the dependent.
    analysis_id              UUID NOT NULL REFERENCES blast_radius_analyses (id),
    dependent_id             BIGINT NOT NULL UNIQUE REFERENCES blast_radius_dependents (id),

Copilot AI review requested due to automatic review settings July 22, 2026 11:09
@ulemons
ulemons force-pushed the feat/add-blast-radius-migrations branch from 99915ef to fbb843b Compare July 22, 2026 11:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:97

  • These two foreign keys are independent, so the database accepts a verdict whose analysis_id belongs to analysis A while dependent_id belongs to analysis B. Because reports aggregate verdicts directly by analysis_id, such a row would silently contaminate the report. Enforce the pair with a composite foreign key (and a matching unique key on dependents), or remove the duplicated analysis_id and derive it through the dependent.
    analysis_id              UUID NOT NULL REFERENCES blast_radius_analyses (id),
    dependent_id             BIGINT NOT NULL UNIQUE REFERENCES blast_radius_dependents (id),

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:89

  • This index duplicates the leftmost prefix of the unique index created by UNIQUE (analysis_id, name). PostgreSQL can use that unique index for analysis_id lookups, so this adds write and storage overhead without enabling another access path.
CREATE INDEX IF NOT EXISTS blast_radius_dependents_analysis_id_idx
    ON blast_radius_dependents (analysis_id);

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:113

  • The following (analysis_id, reachable_verdict) index already supports queries filtering only by its leftmost analysis_id column. Keeping this single-column index duplicates that access path and adds unnecessary write/storage cost.
CREATE INDEX IF NOT EXISTS blast_radius_verdicts_analysis_id_idx
    ON blast_radius_verdicts (analysis_id);

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:135

  • UNIQUE (analysis_id, stage) already creates a B-tree whose leftmost prefix serves analysis_id lookups. This additional index is redundant and increases write amplification and storage.
CREATE INDEX IF NOT EXISTS blast_radius_stage_runs_analysis_id_idx
    ON blast_radius_stage_runs (analysis_id);

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 22, 2026 11:17
@ulemons
ulemons force-pushed the feat/add-blast-radius-migrations branch from fbb843b to fb94246 Compare July 22, 2026 11:17

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fb94246. Configure here.

CREATE TABLE IF NOT EXISTS blast_radius_verdicts (
id BIGSERIAL PRIMARY KEY,
analysis_id UUID NOT NULL REFERENCES blast_radius_analyses (id),
dependent_id BIGINT NOT NULL UNIQUE REFERENCES blast_radius_dependents (id),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdicts allowed for excluded dependents

Medium Severity

The migration documents reachability verdicts as one row per non-excluded dependent, yet blast_radius_verdicts only references blast_radius_dependents by id. Rows with excluded_by_range = true can still get a verdict, which would incorrectly affect true blast-radius totals derived from verdicts.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fb94246. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:97

  • analysis_id and dependent_id are enforced independently, so the database accepts a verdict whose dependent belongs to a different analysis. Any report filtered by blast_radius_verdicts.analysis_id can then attribute that verdict to the wrong job. Make the pair relationally consistent, for example with a composite foreign key to (analysis_id, id) on dependents, or remove the duplicated analysis_id and derive it through the dependent.
    analysis_id              UUID NOT NULL REFERENCES blast_radius_analyses (id),
    dependent_id             BIGINT NOT NULL UNIQUE REFERENCES blast_radius_dependents (id),

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:89

  • This index duplicates the leading-column lookup already provided by UNIQUE (analysis_id, name) on line 85. PostgreSQL can use that unique index for analysis_id = ...; retaining both adds storage and write amplification without adding a query path.
CREATE INDEX IF NOT EXISTS blast_radius_dependents_analysis_id_idx
    ON blast_radius_dependents (analysis_id);

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:113

  • The following (analysis_id, reachable_verdict) index already supports lookups on its leading analysis_id column, making this standalone index redundant. Removing it avoids maintaining two indexes for the same access path.
CREATE INDEX IF NOT EXISTS blast_radius_verdicts_analysis_id_idx
    ON blast_radius_verdicts (analysis_id);

backend/src/osspckgs/migrations/V1784700000__blast_radius_analyses.sql:135

  • UNIQUE (analysis_id, stage) on line 131 already creates an index usable for analysis_id lookups. This additional index is redundant and adds unnecessary storage and write overhead.
CREATE INDEX IF NOT EXISTS blast_radius_stage_runs_analysis_id_idx
    ON blast_radius_stage_runs (analysis_id);

@ulemons
ulemons merged commit 177c7d2 into main Jul 22, 2026
14 checks passed
@ulemons
ulemons deleted the feat/add-blast-radius-migrations branch July 22, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Created by Linear-GitHub Sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants